#include <cstddef>
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include "include\entity.h"
#include "include\textdisplay.h"
#include "include\action.h"

using namespace std;


Entity::Entity(string name) //Constructor
{
    this->name = name;
    health = 0;
    this->SetRandomStats();

    this->healthBar = TextBarMeter(maxHealth, health, 15, "Health");
    this->magicBar = TextBarMeter(maxMagic, magic, 15, "Magic");
    lastAction = new BattleAction();
    lastAction->setActionType(NOTHING);


}

//Begin public methods

void Entity::NewTurn()
{
    list<StatusEffect*>::iterator i = statusEffectList.begin();
    while ( i != statusEffectList.end())
    {
        StatusEffect *pEffect = *i;
        pEffect->ExecuteStatusEffects();
        pEffect->UpdateStatusEffects();
        if (pEffect->GetDuration() < 1)
        {
            statusEffectList.erase(i++);
        }
        i++;
    }
    UpdateMagic();
}

void Entity::SetRandomStats()
{

    attackStrength = rand() % 60;
    defenseStrength = rand() % 60;
    luck = rand() % 10;
    dexterity = rand() % 60;
    maxMagic = (rand() % 100) + 50 ;
    magic = maxMagic / 2;
}

string Entity::GetStatString()
{
    // Really unsure as to what the hell is going on here.
    string number;
    char buffer [256];
    string statString;
    sprintf(buffer, "[Atk: %d] [Def: %d] [Dex: %d] [Luk: %d] [Mag: %d of %d] ", attackStrength, defenseStrength, dexterity, luck, magic, maxMagic);
    return string(buffer);
}

string Entity::GetName()
{
    return name;
}

int Entity::GetHealth()
{
    return health;
}

void Entity::SetHealth(int newHealth)
{
    if (newHealth > 0 && newHealth <= maxHealth)
    {
        health = newHealth;
    }
    else if (newHealth > maxHealth)
    {
        health = maxHealth;
    }
    else
    {
        health = 0;
    }
}

bool Entity::IsPlayer()
{
    return isPlayer;
}

void Entity::SetIsPlayer(bool newIsPlayer)
{
    isPlayer = newIsPlayer;
}


int Entity::GetMaxHealth()
{
    return maxHealth;
}

void Entity::SetMaxHealth(int newMaxHealth)
{
    if (newMaxHealth > 0)
    {
        maxHealth = newMaxHealth;
    }
    else
    {
        maxHealth = 0;
    }
}

int Entity::GetMagic()
{
    return magic;
}

void Entity::SetMagic(int newMagic)
{
    if (newMagic > 0)
    {
        magic = newMagic;
    }
    else
    {
        magic = 0;
    }
}

int Entity::GetMaxMagic()
{
    return maxMagic;
}

void Entity::SetMaxMagic(int newMaxMagic)
{
    if (newMaxMagic > 0)
    {
        maxMagic = newMaxMagic;
    }
    else
    {
        maxMagic = 0;
    }
}

int Entity::GetAttackStrength()
{
    return attackStrength;
}

void Entity::SetAttackStrength(int newAttackStrength)
{
    if (newAttackStrength > 0)
    {
        attackStrength = newAttackStrength;
    }
    else
    {
        attackStrength = 0;
    }
}

void Entity::SetDefenseStrength(int newDefenseStrength)
{
    if (newDefenseStrength > 0)
    {
        defenseStrength = newDefenseStrength;
    }
    else
    {
        defenseStrength = 0;
    }
}

int Entity::GetDefenseStrength()
{
    if (EntityHasStatusEffect(DEFENDING))
    {
        return defenseStrength * 2;
    }
    else
    {
        return defenseStrength;
    }

}

int Entity::GetLuck()
{
    return luck;
}

void Entity::SetLuck(int newLuck)
{
    if (newLuck > 0)
    {
        luck = newLuck;
    }
    else
    {
        luck = 0;
    }
}

int Entity::GetDexterity()
{
    if (EntityHasStatusEffect(DEFENDING))
    {
        return dexterity * 2;
    }
    else
    {
        return dexterity;
    }
}

void Entity::SetDexterity(int newDexterity)
{
    if (newDexterity > 0)
    {
        dexterity = newDexterity;
    }
    else
    {
        dexterity = 0;
    }
}

void Entity::SetStatus(StatusEffectType type, int duration, int magnitude)
{
    StatusEffect *NewStatusEffect = new StatusEffect(type, duration, magnitude, this);
    statusEffectList.push_back(NewStatusEffect);
}

void Entity::ListStatusEffects()
{
    for (list<StatusEffect*>::iterator i = statusEffectList.begin(); i != statusEffectList.end(); ++i)
    {

        StatusEffect *pEffect = *i;
        pEffect->Display();
    }
}

//End public methods, begin private methods

bool Entity::EntityHasStatusEffect(StatusEffectType type)
{
    for (list<StatusEffect*>::iterator i = statusEffectList.begin(); i != statusEffectList.end(); ++i)
    {
        StatusEffect *pEffect = *i;
        if (pEffect->GetType() == type)
        {
            return true;
        }
    }
    return false;
}

void Entity::UpdateMagic() // This will be more sophisticated later, with varying rates of recharge and stuff
{
    if (magic < maxMagic)
    {
        magic = magic + 4;
        if (magic > maxMagic)
        {
            magic = maxMagic;
        }
    }
}

void Entity::Display()
{
    cout << endl << "----" << this->name << "----------------------------------------" << endl;
    cout << "Stats: " << GetStatString() << endl;
    healthBar.SetTotal(maxHealth);
    healthBar.SetValue(health);
    healthBar.Display();
    cout << "  ";
    magicBar.SetTotal(maxMagic);
    magicBar.SetValue(magic);
    magicBar.Display();
    cout << endl;
    ListStatusEffects();
    cout << endl;



}


ActionType Entity::getAction() // This will obviously need to be generalized with no hard-coding for more than one enemy
{
    bool actionExecuted = false; // Just make this an endless loop later? That is it in effect now.
    while (!actionExecuted && name == "Player")
    {
        ActionType playerActionType = lastAction->GetPlayerAction(this);
        if (playerActionType != NOTHING)
        {
            return playerActionType;
        }
    }
    return lastAction->GetEnemyAction(this);
}


void Entity::ExecuteAction(ActionType thisTurnAction, Entity *actionSubject, Entity *actionObject)
{
    lastAction->ExecuteAction(thisTurnAction, this, actionObject);
}

void Entity::DisplayLastAction()
{
    if (lastAction->getActionType() != NOTHING)
    {
        cout << "ACTION: " << name << " used " << lastAction->GetActionName() << " and " << lastAction->GetActionResultString() << endl;
    }
}
